from os.path import dirname, basename, realpath

import bpy
import os
import random
from bpy.props import PointerProperty, FloatProperty, EnumProperty, StringProperty, IntProperty, BoolProperty
from bpy.types import AddonPreferences
from bpy.types import PropertyGroup

from . import asset_items, asset_tree
from .prefer import Preferences
from ..log import log
from ...ops.asset import ClearAsset, LoadAsset
from ...rsc import asset_path


class AssetPointer(PropertyGroup, Preferences):
    """资产属性
    资产的所有项都放在这个里面
    """
    asset_tree: PointerProperty(type=asset_tree.TreePointer)
    asset_items: PointerProperty(type=asset_items.AssetItemsPointer)


class ImportProperty:
    import_mode: EnumProperty(
        name='导入模式',
        description='导入模式',
        items=[
            ('PREVIEW', '预览', '''将资产导入到临时的集合,如果连续点了两下都是一个预览就直接导入了'''),
            ('IMPORT', '直接导入', '''直接导入资产到活动'''),

        ],
        default='IMPORT',
    )

    import_link: BoolProperty(
        name='关联导入',
        description='关联导入资产',
        default=False,
    )

    import_to_active_collect: BoolProperty(
        name='导入到活动集合',
        description='导入到活动集合里面',
        default=True,
    )
    import_use_fake_user: BoolProperty(
        name='导入为伪用户',
        description='导入的资产将会设置为伪用户',
        default=False,
    )
    import_set_parent_form_tag: BoolProperty(
        name='设置父级',
        default=False,
        description='导入时如果有TAG-前缀的将会把导入的资产父级设置为TAG物体'
    )
    import_whole_scene: BoolProperty(name='导入为新场景',
                                     description=(
                                         '将blend资产内的场景导入作为活动场景,而不是导入资产场景内的物体'
                                         '同时将会把渲染的数据同时导入'
                                         '如果不勾选将会导入作为物体'
                                     ),
                                     default=True)

    @property
    def import_conflict(self):
        """反回是否导入冲突的布尔值
        更改位置的属性只能开启一个
        """
        return self.import_to_cursor and self.import_to_location_box

    def update_import_to_cursor(self, context):
        if self.import_conflict:
            self.import_to_location_box = False

    def update_import_to_location(self, context):

        if self.import_conflict:
            self.import_to_cursor = False

    import_to_location_box: BoolProperty(
        name='导入到定位框',
        description='只有当场景里面有 TAG-前缀物体时此属性才有效',
        update=update_import_to_location
    )

    import_to_cursor: BoolProperty(
        name='导入到游标',
        description='将导入物体的位置和旋转导入到游标位置,缩放将为1',
        default=False,
        update=update_import_to_cursor
    )


class AssetProperty:
    asset_pointer: PointerProperty(type=AssetPointer)

    def update_mode(self, context):
        """更新场景队列"""
        self.update_queue_scene()

    mode: EnumProperty(
        name='插件运行模式',
        items=[('ASSET', '资产', '导入资产',),
               ('OBJECT', '物体', '选择一个物体保侍不变,选择多个场景进行替换导出并渲染'),
               ('SCENE', '场景', '场景保侍不变,替换物体'),
               ('POOL', '池', '选择产品池和场景池,用于遍历输出渲染文件',),
               ],
        update=update_mode,
    )

    asset_root_path: StringProperty(
        name='资产根目录路径',
        subtype='DIR_PATH',
        default=asset_path,
    )


class ViewProperty:
    _show_type_items = [(key, key.title(), key.title())
                        for key in Preferences.show_asset_type_item]

    def show_type_items(self, context):
        items = self._show_type_items.copy()
        if not self.is_asset_mode:  # 不是资产模式就显示
            # 任务列表
            items.extend([('RENDER_QUEUE', '渲染列表', '批量渲染 添加渲染队列',), ])
        return items

    def _get_show_type(self):
        """通过获取和设置值,来记录每一个界面所选择的类型"""
        mode = self.mode.lower()
        key = f'show_type_{mode}'

        if key not in self:
            # default
            return 1
        return self[key]

    def _set_show_type(self, value):
        """"""
        mode = self.mode.lower()
        key = f'show_type_{mode}'
        self[key] = value

    def update_show_type(self, context):
        """更新场景队列"""
        self.update_queue_scene()

    show_type: EnumProperty(name='显示类型',
                            items=show_type_items,
                            get=_get_show_type,
                            set=_set_show_type,
                            update=update_show_type
                            )

    export_assign_file_count: IntProperty(name='输出文件数量',
                                          description='场景匹配时输出文件的数量',
                                          min=1,
                                          default=5,
                                          )

    icon_size: FloatProperty(
        name='图标大小',
        default=5,
        min=0,
        max=20,
    )

    load_preview_icon_size: EnumProperty(
        name='预览图像大小',
        items=[(i, i, i) for i in ('128', '256', '512', '1024')],
    )

    def update_search(self, context):
        log.info(f'update_search {self}', )
        context.area.tag_redraw()

    search_asset_string: StringProperty(name='搜索资产', update=update_search,
                                        options={'TEXTEDIT_UPDATE'})

    show_preferences_property: BoolProperty(name='偏好设置')

    def draw(self, context):
        self.draw_pref(self.layout)

    @staticmethod
    def draw_pref(layout: 'bpy.types.UILayout'):
        pref = Preferences.pref_()

        layout.use_property_split = True
        layout.use_property_decorate = True

        layout.prop(pref, 'icon_size')
        layout.prop(pref, 'load_preview_icon_size')
        layout.prop(pref, 'show_type')

        row = layout.row()
        row.alert = not os.path.isdir(pref.asset_root_path)
        row.prop(pref, 'asset_root_path')

        layout.separator()
        layout.operator(LoadAsset.bl_idname)
        layout.operator(ClearAsset.bl_idname)


class AddonProperty(AddonPreferences,
                    ImportProperty,
                    AssetProperty,
                    ViewProperty,
                    Preferences,
                    ):
    """插件属性类
    存放所有插件属性的
    """
    bl_idname = basename(dirname(dirname(dirname(realpath(__file__)))))

    @property
    def allow_add_queue(self) -> bool:
        """允许添加队列的布尔值
        用于设置添加操作符是否可用"""
        se_ob = self.selected_objects
        se_sc = self.selected_scenes

        pool = self.is_pool_mode and se_ob and se_sc  # 是池模式并且选了物体和场景的
        scene = self.is_scene_mode
        obj = self.is_object_mode and se_sc  # 是物体模式选了场景的
        return bool(pool or scene or obj)

    @property
    def pop_object(self):
        """测试用
        随机取一个物体"""
        objects = self.pref.active_objects.values()
        if len(objects):
            random.shuffle(objects)
            return random.choice(objects)
        else:
            log.error(f"{self} render_master 无物体")

    @property
    def pop_scene(self):
        """测试用
        随机取一个场景
        """
        scenes = self.pref.active_scenes.values()
        if len(scenes):
            random.shuffle(scenes)
            scene = random.choice(scenes)
            return scene
        else:
            log.error(f"{self} render_master 无场景")

    @property
    def pop_folder_object(self):
        obj = self.pop_object
        return obj.folder_path

    @property
    def pop_select_collect(self):
        collections = self.selected_collect_items.values()
        random.shuffle(collections)
        col = random.choice(collections)
        return col


mod_tuple = (
    # 子属性类的文件
    asset_items,
    asset_tree,
)

class_tuple = (
    AssetPointer,
    AddonProperty,
)

register_class, unregister_class = bpy.utils.register_classes_factory(
    class_tuple)


def register():
    for mod in mod_tuple:
        mod.register()
    register_class()


def unregister():
    for mod in mod_tuple[::-1]:
        mod.unregister()
    unregister_class()
